/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package it.polimi.games.epkb.controller;

import it.polimi.games.epkb.controller.exceptions.IllegalOrphanException;
import it.polimi.games.epkb.controller.exceptions.NonexistentEntityException;
import it.polimi.games.epkb.controller.exceptions.PreexistingEntityException;
import it.polimi.games.epkb.entityClasses.Server;
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import it.polimi.games.epkb.entityClasses.Component;
import it.polimi.games.epkb.entityClasses.Rack;
import it.polimi.games.epkb.entityClasses.Disk;
import java.util.ArrayList;
import java.util.Collection;
import it.polimi.games.epkb.entityClasses.NetworkInterface;
import it.polimi.games.epkb.entityClasses.Cpu;
import it.polimi.games.epkb.entityClasses.Memory;
import javax.transaction.UserTransaction;

/**
 *
 * @author plebani
 */
public class ServerJpaController implements Serializable {

    public ServerJpaController(EntityManagerFactory emf) {
        this.utx = null;
        this.emf = emf;
    }

    public ServerJpaController(UserTransaction utx, EntityManagerFactory emf) {
        this.utx = utx;
        this.emf = emf;
    }
    private UserTransaction utx = null;
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Server server) throws IllegalOrphanException, PreexistingEntityException, Exception {
        if (server.getDiskCollection() == null) {
            server.setDiskCollection(new ArrayList<Disk>());
        }
        if (server.getNetworkInterfaceCollection() == null) {
            server.setNetworkInterfaceCollection(new ArrayList<NetworkInterface>());
        }
        if (server.getCpuCollection() == null) {
            server.setCpuCollection(new ArrayList<Cpu>());
        }
        if (server.getMemoryCollection() == null) {
            server.setMemoryCollection(new ArrayList<Memory>());
        }
        List<String> illegalOrphanMessages = null;
        Component componentOrphanCheck = server.getComponent();
        if (componentOrphanCheck != null) {
            Server oldServerOfComponent = componentOrphanCheck.getServer();
            if (oldServerOfComponent != null) {
                if (illegalOrphanMessages == null) {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("The Component " + componentOrphanCheck + " already has an item of type Server whose component column cannot be null. Please make another selection for the component field.");
            }
        }
        if (illegalOrphanMessages != null) {
            throw new IllegalOrphanException(illegalOrphanMessages);
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Component component = server.getComponent();
            if (component != null) {
                component = em.getReference(component.getClass(), component.getId());
                server.setComponent(component);
            }
            Rack idRack = server.getIdRack();
            if (idRack != null) {
                idRack = em.getReference(idRack.getClass(), idRack.getId());
                server.setIdRack(idRack);
            }
            Collection<Disk> attachedDiskCollection = new ArrayList<Disk>();
            for (Disk diskCollectionDiskToAttach : server.getDiskCollection()) {
                diskCollectionDiskToAttach = em.getReference(diskCollectionDiskToAttach.getClass(), diskCollectionDiskToAttach.getId());
                attachedDiskCollection.add(diskCollectionDiskToAttach);
            }
            server.setDiskCollection(attachedDiskCollection);
            Collection<NetworkInterface> attachedNetworkInterfaceCollection = new ArrayList<NetworkInterface>();
            for (NetworkInterface networkInterfaceCollectionNetworkInterfaceToAttach : server.getNetworkInterfaceCollection()) {
                networkInterfaceCollectionNetworkInterfaceToAttach = em.getReference(networkInterfaceCollectionNetworkInterfaceToAttach.getClass(), networkInterfaceCollectionNetworkInterfaceToAttach.getId());
                attachedNetworkInterfaceCollection.add(networkInterfaceCollectionNetworkInterfaceToAttach);
            }
            server.setNetworkInterfaceCollection(attachedNetworkInterfaceCollection);
            Collection<Cpu> attachedCpuCollection = new ArrayList<Cpu>();
            for (Cpu cpuCollectionCpuToAttach : server.getCpuCollection()) {
                cpuCollectionCpuToAttach = em.getReference(cpuCollectionCpuToAttach.getClass(), cpuCollectionCpuToAttach.getId());
                attachedCpuCollection.add(cpuCollectionCpuToAttach);
            }
            server.setCpuCollection(attachedCpuCollection);
            Collection<Memory> attachedMemoryCollection = new ArrayList<Memory>();
            for (Memory memoryCollectionMemoryToAttach : server.getMemoryCollection()) {
                memoryCollectionMemoryToAttach = em.getReference(memoryCollectionMemoryToAttach.getClass(), memoryCollectionMemoryToAttach.getId());
                attachedMemoryCollection.add(memoryCollectionMemoryToAttach);
            }
            server.setMemoryCollection(attachedMemoryCollection);
            em.persist(server);
            if (component != null) {
                component.setServer(server);
                component = em.merge(component);
            }
            if (idRack != null) {
                idRack.getServerCollection().add(server);
                idRack = em.merge(idRack);
            }
            for (Disk diskCollectionDisk : server.getDiskCollection()) {
                Server oldIdServerOfDiskCollectionDisk = diskCollectionDisk.getIdServer();
                diskCollectionDisk.setIdServer(server);
                diskCollectionDisk = em.merge(diskCollectionDisk);
                if (oldIdServerOfDiskCollectionDisk != null) {
                    oldIdServerOfDiskCollectionDisk.getDiskCollection().remove(diskCollectionDisk);
                    oldIdServerOfDiskCollectionDisk = em.merge(oldIdServerOfDiskCollectionDisk);
                }
            }
            for (NetworkInterface networkInterfaceCollectionNetworkInterface : server.getNetworkInterfaceCollection()) {
                Server oldIdServerOfNetworkInterfaceCollectionNetworkInterface = networkInterfaceCollectionNetworkInterface.getIdServer();
                networkInterfaceCollectionNetworkInterface.setIdServer(server);
                networkInterfaceCollectionNetworkInterface = em.merge(networkInterfaceCollectionNetworkInterface);
                if (oldIdServerOfNetworkInterfaceCollectionNetworkInterface != null) {
                    oldIdServerOfNetworkInterfaceCollectionNetworkInterface.getNetworkInterfaceCollection().remove(networkInterfaceCollectionNetworkInterface);
                    oldIdServerOfNetworkInterfaceCollectionNetworkInterface = em.merge(oldIdServerOfNetworkInterfaceCollectionNetworkInterface);
                }
            }
            for (Cpu cpuCollectionCpu : server.getCpuCollection()) {
                Server oldIdServerOfCpuCollectionCpu = cpuCollectionCpu.getIdServer();
                cpuCollectionCpu.setIdServer(server);
                cpuCollectionCpu = em.merge(cpuCollectionCpu);
                if (oldIdServerOfCpuCollectionCpu != null) {
                    oldIdServerOfCpuCollectionCpu.getCpuCollection().remove(cpuCollectionCpu);
                    oldIdServerOfCpuCollectionCpu = em.merge(oldIdServerOfCpuCollectionCpu);
                }
            }
            for (Memory memoryCollectionMemory : server.getMemoryCollection()) {
                Server oldIdServerOfMemoryCollectionMemory = memoryCollectionMemory.getIdServer();
                memoryCollectionMemory.setIdServer(server);
                memoryCollectionMemory = em.merge(memoryCollectionMemory);
                if (oldIdServerOfMemoryCollectionMemory != null) {
                    oldIdServerOfMemoryCollectionMemory.getMemoryCollection().remove(memoryCollectionMemory);
                    oldIdServerOfMemoryCollectionMemory = em.merge(oldIdServerOfMemoryCollectionMemory);
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            if (findServer(server.getId()) != null) {
                throw new PreexistingEntityException("Server " + server + " already exists.", ex);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Server server) throws IllegalOrphanException, NonexistentEntityException, Exception {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Server persistentServer = em.find(Server.class, server.getId());
            Component componentOld = persistentServer.getComponent();
            Component componentNew = server.getComponent();
            Rack idRackOld = persistentServer.getIdRack();
            Rack idRackNew = server.getIdRack();
            Collection<Disk> diskCollectionOld = persistentServer.getDiskCollection();
            Collection<Disk> diskCollectionNew = server.getDiskCollection();
            Collection<NetworkInterface> networkInterfaceCollectionOld = persistentServer.getNetworkInterfaceCollection();
            Collection<NetworkInterface> networkInterfaceCollectionNew = server.getNetworkInterfaceCollection();
            Collection<Cpu> cpuCollectionOld = persistentServer.getCpuCollection();
            Collection<Cpu> cpuCollectionNew = server.getCpuCollection();
            Collection<Memory> memoryCollectionOld = persistentServer.getMemoryCollection();
            Collection<Memory> memoryCollectionNew = server.getMemoryCollection();
            List<String> illegalOrphanMessages = null;
            if (componentNew != null && !componentNew.equals(componentOld)) {
                Server oldServerOfComponent = componentNew.getServer();
                if (oldServerOfComponent != null) {
                    if (illegalOrphanMessages == null) {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("The Component " + componentNew + " already has an item of type Server whose component column cannot be null. Please make another selection for the component field.");
                }
            }
            if (illegalOrphanMessages != null) {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            if (componentNew != null) {
                componentNew = em.getReference(componentNew.getClass(), componentNew.getId());
                server.setComponent(componentNew);
            }
            if (idRackNew != null) {
                idRackNew = em.getReference(idRackNew.getClass(), idRackNew.getId());
                server.setIdRack(idRackNew);
            }
            Collection<Disk> attachedDiskCollectionNew = new ArrayList<Disk>();
            for (Disk diskCollectionNewDiskToAttach : diskCollectionNew) {
                diskCollectionNewDiskToAttach = em.getReference(diskCollectionNewDiskToAttach.getClass(), diskCollectionNewDiskToAttach.getId());
                attachedDiskCollectionNew.add(diskCollectionNewDiskToAttach);
            }
            diskCollectionNew = attachedDiskCollectionNew;
            server.setDiskCollection(diskCollectionNew);
            Collection<NetworkInterface> attachedNetworkInterfaceCollectionNew = new ArrayList<NetworkInterface>();
            for (NetworkInterface networkInterfaceCollectionNewNetworkInterfaceToAttach : networkInterfaceCollectionNew) {
                networkInterfaceCollectionNewNetworkInterfaceToAttach = em.getReference(networkInterfaceCollectionNewNetworkInterfaceToAttach.getClass(), networkInterfaceCollectionNewNetworkInterfaceToAttach.getId());
                attachedNetworkInterfaceCollectionNew.add(networkInterfaceCollectionNewNetworkInterfaceToAttach);
            }
            networkInterfaceCollectionNew = attachedNetworkInterfaceCollectionNew;
            server.setNetworkInterfaceCollection(networkInterfaceCollectionNew);
            Collection<Cpu> attachedCpuCollectionNew = new ArrayList<Cpu>();
            for (Cpu cpuCollectionNewCpuToAttach : cpuCollectionNew) {
                cpuCollectionNewCpuToAttach = em.getReference(cpuCollectionNewCpuToAttach.getClass(), cpuCollectionNewCpuToAttach.getId());
                attachedCpuCollectionNew.add(cpuCollectionNewCpuToAttach);
            }
            cpuCollectionNew = attachedCpuCollectionNew;
            server.setCpuCollection(cpuCollectionNew);
            Collection<Memory> attachedMemoryCollectionNew = new ArrayList<Memory>();
            for (Memory memoryCollectionNewMemoryToAttach : memoryCollectionNew) {
                memoryCollectionNewMemoryToAttach = em.getReference(memoryCollectionNewMemoryToAttach.getClass(), memoryCollectionNewMemoryToAttach.getId());
                attachedMemoryCollectionNew.add(memoryCollectionNewMemoryToAttach);
            }
            memoryCollectionNew = attachedMemoryCollectionNew;
            server.setMemoryCollection(memoryCollectionNew);
            server = em.merge(server);
            if (componentOld != null && !componentOld.equals(componentNew)) {
                componentOld.setServer(null);
                componentOld = em.merge(componentOld);
            }
            if (componentNew != null && !componentNew.equals(componentOld)) {
                componentNew.setServer(server);
                componentNew = em.merge(componentNew);
            }
            if (idRackOld != null && !idRackOld.equals(idRackNew)) {
                idRackOld.getServerCollection().remove(server);
                idRackOld = em.merge(idRackOld);
            }
            if (idRackNew != null && !idRackNew.equals(idRackOld)) {
                idRackNew.getServerCollection().add(server);
                idRackNew = em.merge(idRackNew);
            }
            for (Disk diskCollectionOldDisk : diskCollectionOld) {
                if (!diskCollectionNew.contains(diskCollectionOldDisk)) {
                    diskCollectionOldDisk.setIdServer(null);
                    diskCollectionOldDisk = em.merge(diskCollectionOldDisk);
                }
            }
            for (Disk diskCollectionNewDisk : diskCollectionNew) {
                if (!diskCollectionOld.contains(diskCollectionNewDisk)) {
                    Server oldIdServerOfDiskCollectionNewDisk = diskCollectionNewDisk.getIdServer();
                    diskCollectionNewDisk.setIdServer(server);
                    diskCollectionNewDisk = em.merge(diskCollectionNewDisk);
                    if (oldIdServerOfDiskCollectionNewDisk != null && !oldIdServerOfDiskCollectionNewDisk.equals(server)) {
                        oldIdServerOfDiskCollectionNewDisk.getDiskCollection().remove(diskCollectionNewDisk);
                        oldIdServerOfDiskCollectionNewDisk = em.merge(oldIdServerOfDiskCollectionNewDisk);
                    }
                }
            }
            for (NetworkInterface networkInterfaceCollectionOldNetworkInterface : networkInterfaceCollectionOld) {
                if (!networkInterfaceCollectionNew.contains(networkInterfaceCollectionOldNetworkInterface)) {
                    networkInterfaceCollectionOldNetworkInterface.setIdServer(null);
                    networkInterfaceCollectionOldNetworkInterface = em.merge(networkInterfaceCollectionOldNetworkInterface);
                }
            }
            for (NetworkInterface networkInterfaceCollectionNewNetworkInterface : networkInterfaceCollectionNew) {
                if (!networkInterfaceCollectionOld.contains(networkInterfaceCollectionNewNetworkInterface)) {
                    Server oldIdServerOfNetworkInterfaceCollectionNewNetworkInterface = networkInterfaceCollectionNewNetworkInterface.getIdServer();
                    networkInterfaceCollectionNewNetworkInterface.setIdServer(server);
                    networkInterfaceCollectionNewNetworkInterface = em.merge(networkInterfaceCollectionNewNetworkInterface);
                    if (oldIdServerOfNetworkInterfaceCollectionNewNetworkInterface != null && !oldIdServerOfNetworkInterfaceCollectionNewNetworkInterface.equals(server)) {
                        oldIdServerOfNetworkInterfaceCollectionNewNetworkInterface.getNetworkInterfaceCollection().remove(networkInterfaceCollectionNewNetworkInterface);
                        oldIdServerOfNetworkInterfaceCollectionNewNetworkInterface = em.merge(oldIdServerOfNetworkInterfaceCollectionNewNetworkInterface);
                    }
                }
            }
            for (Cpu cpuCollectionOldCpu : cpuCollectionOld) {
                if (!cpuCollectionNew.contains(cpuCollectionOldCpu)) {
                    cpuCollectionOldCpu.setIdServer(null);
                    cpuCollectionOldCpu = em.merge(cpuCollectionOldCpu);
                }
            }
            for (Cpu cpuCollectionNewCpu : cpuCollectionNew) {
                if (!cpuCollectionOld.contains(cpuCollectionNewCpu)) {
                    Server oldIdServerOfCpuCollectionNewCpu = cpuCollectionNewCpu.getIdServer();
                    cpuCollectionNewCpu.setIdServer(server);
                    cpuCollectionNewCpu = em.merge(cpuCollectionNewCpu);
                    if (oldIdServerOfCpuCollectionNewCpu != null && !oldIdServerOfCpuCollectionNewCpu.equals(server)) {
                        oldIdServerOfCpuCollectionNewCpu.getCpuCollection().remove(cpuCollectionNewCpu);
                        oldIdServerOfCpuCollectionNewCpu = em.merge(oldIdServerOfCpuCollectionNewCpu);
                    }
                }
            }
            for (Memory memoryCollectionOldMemory : memoryCollectionOld) {
                if (!memoryCollectionNew.contains(memoryCollectionOldMemory)) {
                    memoryCollectionOldMemory.setIdServer(null);
                    memoryCollectionOldMemory = em.merge(memoryCollectionOldMemory);
                }
            }
            for (Memory memoryCollectionNewMemory : memoryCollectionNew) {
                if (!memoryCollectionOld.contains(memoryCollectionNewMemory)) {
                    Server oldIdServerOfMemoryCollectionNewMemory = memoryCollectionNewMemory.getIdServer();
                    memoryCollectionNewMemory.setIdServer(server);
                    memoryCollectionNewMemory = em.merge(memoryCollectionNewMemory);
                    if (oldIdServerOfMemoryCollectionNewMemory != null && !oldIdServerOfMemoryCollectionNewMemory.equals(server)) {
                        oldIdServerOfMemoryCollectionNewMemory.getMemoryCollection().remove(memoryCollectionNewMemory);
                        oldIdServerOfMemoryCollectionNewMemory = em.merge(oldIdServerOfMemoryCollectionNewMemory);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                String id = server.getId();
                if (findServer(id) == null) {
                    throw new NonexistentEntityException("The server with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(String id) throws NonexistentEntityException {
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Server server;
            try {
                server = em.getReference(Server.class, id);
                server.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The server with id " + id + " no longer exists.", enfe);
            }
            Component component = server.getComponent();
            if (component != null) {
                component.setServer(null);
                component = em.merge(component);
            }
            Rack idRack = server.getIdRack();
            if (idRack != null) {
                idRack.getServerCollection().remove(server);
                idRack = em.merge(idRack);
            }
            Collection<Disk> diskCollection = server.getDiskCollection();
            for (Disk diskCollectionDisk : diskCollection) {
                diskCollectionDisk.setIdServer(null);
                diskCollectionDisk = em.merge(diskCollectionDisk);
            }
            Collection<NetworkInterface> networkInterfaceCollection = server.getNetworkInterfaceCollection();
            for (NetworkInterface networkInterfaceCollectionNetworkInterface : networkInterfaceCollection) {
                networkInterfaceCollectionNetworkInterface.setIdServer(null);
                networkInterfaceCollectionNetworkInterface = em.merge(networkInterfaceCollectionNetworkInterface);
            }
            Collection<Cpu> cpuCollection = server.getCpuCollection();
            for (Cpu cpuCollectionCpu : cpuCollection) {
                cpuCollectionCpu.setIdServer(null);
                cpuCollectionCpu = em.merge(cpuCollectionCpu);
            }
            Collection<Memory> memoryCollection = server.getMemoryCollection();
            for (Memory memoryCollectionMemory : memoryCollection) {
                memoryCollectionMemory.setIdServer(null);
                memoryCollectionMemory = em.merge(memoryCollectionMemory);
            }
            em.remove(server);
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<Server> findServerEntities() {
        return findServerEntities(true, -1, -1);
    }

    public List<Server> findServerEntities(int maxResults, int firstResult) {
        return findServerEntities(false, maxResults, firstResult);
    }

    private List<Server> findServerEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Server.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Server findServer(String id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Server.class, id);
        } finally {
            em.close();
        }
    }

    public int getServerCount() {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<Server> rt = cq.from(Server.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }
    
}
